/**
 * SSP for WEB
 * Copyright 2015 Baidu Inc. All rights reserved.
 *
 * @file 容器控件的浮层扩展
 * @exports ui.extension.ContainerOverlay
 * @author shenbin(shenbin01@baidu.com)
 */
define(
    function (require) {
        require('esui/Overlay');

        var etpl = require('etpl');
        var ui = require('esui');
        var u = require('common/util');

        var plainRenderer = etpl.compile('<p>${data}</p>');
        var arrayifyRenderer = etpl.compile('<!-- for: ${data} as ${content} --><p>${content}</p><!-- /for -->');

        /*
         * ## 浮层启用控制
         *
         * 需要触发浮层的元素，必须拥有一个 `data-container-overlay-enabled = "true"` 的属性
         *
         * ## 浮层数据源
         *
         * 假设扩展绑定控件的数据源为 datasource
         *
         * 若当前点击元素或其祖先节点拥有 `data-container-overlay-field` 属性，则将其作为浮层倚靠元素
         * 扩展使用指定属性的属性值作为浮层的数据来源
         *
         * 1. 当浮层触发时，从当前点击元素开始向上层冒泡查找拥有 `data-row` 属性的祖先节点
         * 2.1 若找到对应元素，则使用 datasource[rowIndex][field]
         * 2.2 若直到扩展绑定控件所在的祖先节点扔未找到，不再继续向上层查找，使用 datasource[field]
         *
         * 若倚靠元素没有 `data-container-overlay-field` 属性，则扩展使用整个datasource作为浮层的数据来源
         *
         * ## 浮层渲染模板
         *
         * 若倚靠元素没有 `data-container-overlay-templateTarget` 属性，则使用扩展默认的模板渲染
         * 若倚靠元素有 `data-container-overlay-templateTarget` 属性，则使用指定的模板渲染
         *
         * 默认的模板渲染时所使用的数据源支持 `可字符串化` 与 `可字符串化数据组成的数组` 两种格式
         * 如果需要提供的是结构化的数据，使用自定义的 `templateTarget`
         */

        /**
         * @class ui.extension.ContainerOverlay
         * @extends esui.Extension
         */
        var exports = {};

        /**
         * @property {string} ui.extension.ContainerOverlay#type
         */
        exports.type = 'ContainerOverlay';

        /**
         * 获取触发元素的所关联数据的字段名
         *
         * @protected
         * @method ui.extension.ContainerOverlay#getDatasourceField
         * @param {HTMLElement} element 元素
         * @return {string|null}
         */
        exports.getDatasourceField = function (element) {
            return element.getAttribute('data-container-overlay-field');
        };

        /**
         * 获取指定元素在容器中的所处行数
         *
         * @param {HTMLElement} element 元素
         * @return {number|null}
         */
        function getRow(element) {
            var containerElement = this.target.main;
            var row = element.getAttribute('data-row');

            while (!row && element.parentNode && element.parentNode !== containerElement) {
                element = element.parentNode;
                row = element.getAttribute('data-row');
            }

            return row;
        }

        /**
         * 获取overlay所需填充的数据
         *
         * @protected
         * @method ui.extension.ContainerOverlay#getOverlayData
         * @param {HTMLElement} element 元素
         * @return {Mixed}
         */
        exports.getOverlayData = function (element) {
            var overlayField = this.getDatasourceField(element);
            var datasource = this.target.get('datasource');

            if (!overlayField) {
                return datasource;
            }

            var row = getRow.call(this, element);

            return row ? datasource[row][overlayField] : datasource[overlayField];
        };

        /**
         * 获取overlay填充的模板渲染器
         *
         * @protected
         * @method ui.extension.ContainerOverlay#getOverlayRenderer
         * @param {HTMLElement} element 元素
         * @param {Object} data 填充数据
         * @return {Renderer} 渲染器
         */
        exports.getOverlayRenderer = function (element, data) {
            var templateTarget = element.getAttribute('data-container-overlay-template-target');
            var renderer = null;

            if (templateTarget) {
                renderer = etpl.getRenderer(templateTarget);
            }
            else {
                if (u.isArray(data)) {
                    renderer = arrayifyRenderer;
                }
                else {
                    renderer = plainRenderer;
                }
            }

            return renderer;
        };

        /**
         * 获取overlay内容
         *
         * @protected
         * @method ui.extension.ContainerOverlay#getOverlayContent
         * @param {HTMLElement} element 元素
         * @return {string}
         */
        exports.getOverlayContent = function (element) {
            var overlayData = this.getOverlayData(element);
            var overlayRenderer = this.getOverlayRenderer(element, overlayData);

            return overlayRenderer({data: overlayData});
        };

        /**
         * 鼠标点击容器时触发事件的处理
         *
         * @protected
         * @method ui.extension.ContainerOverlay#handleClickContainer
         * @param {HTMLElement} element 元素
         */
        exports.handleClickContainer = function (element) {
            var overlay = this.target.getChild('container-overlay');

            overlay.set('attachedDOM', element);
            overlay.setContent(this.getOverlayContent(element));
            overlay.show();
        };

        /**
         * 获取浮层需要倚靠的目标元素
         *
         * @protected
         * @method ui.extension.ContainerOverlay#getTargetElement
         * @param {HTMLElement} element 元素
         * @return {boolean}
         */
        exports.getTargetElement = function (element) {
            var topElement = this.target.main.parentNode;

            while (!element.getAttribute('data-container-overlay-enabled')
                && element.parentNode
                && element.parentNode !== topElement
            ) {
                element = element.parentNode;
            }

            return element.getAttribute('data-container-overlay-enabled') ? element : null;
        };

        /**
         * 鼠标点击容器时触发的事件
         *
         * @event
         * @param {mini-event.Event} e 事件对象
         */
        function onClickContainer(e) {
            var element = this.getTargetElement(e.target);

            // 在指定元素上点击才触发事件
            if (element) {
                this.handleClickContainer(element);
                e.stopPropagation();
            }
        }

        /**
         * 鼠标点击浮层时触发的事件
         *
         * @event
         * @param {mini-event.Event} e 事件对象
         */
        function onClickOverlay(e) {
            e.stopPropagation();
        }

        /**
         * 鼠标点击全局元素时触发事件的处理
         *
         * @protected
         * @method ui.extension.ContainerOverlay#handleClickDocument
         */
        exports.handleClickDocument = function () {
            var overlay = this.target.getChild('container-overlay');
            overlay.hide();
        };

        /**
         * 鼠标点击全局区域时触发的事件
         *
         * @event
         * @param {mini-event.Event} e 事件对象
         */
        function onClickDocument(e) {
            this.handleClickDocument();
        }

        /**
         * @override
         */
        exports.activate = function () {
            this.$super(arguments);

            var container = this.target;

            // 鼠标点击容器事件的注册
            container.helper.addDOMEvent(container.main, 'click', u.bind(onClickContainer, this));

            // 点击时动态创建的`Overlay`，本身不能作为关闭的点击元素
            // 需要激活时注册浮层元素的点击事件
            // 因此先在激活扩展时创建一个`Overlay`的实例
            var overlay = ui.create(
                'Overlay',
                {
                    autoClose: false,
                    skin: 'container-overlay'
                }
            );
            container.addChild(overlay, 'container-overlay');
            overlay.appendTo(container);

            // 鼠标点击其他区域事件的注册
            container.helper.addDOMEvent(overlay.main, 'click', u.bind(onClickOverlay, this));
            container.helper.addDOMEvent(document, 'click', u.bind(onClickDocument, this));
        };

        var Extension = require('esui/Extension');
        var ContainerOverlay = require('eoo').create(Extension, exports);
        require('esui').registerExtension(ContainerOverlay);

        return ContainerOverlay;
    }
);
